

#include "AudioBuffQueue.h"
#include <stdlib.h>

//#include "log.h"

AudioBuffQueue::AudioBuffQueue()
: _tempBuff(NULL)
, _tempBuffLen(0)
{
}

AudioBuffQueue::~AudioBuffQueue()
{
    clean();
    if (_tempBuff) {
        delete[] _tempBuff;
        _tempBuff = NULL;
    }

}

//
int AudioBuffQueue::setStreamSize(int size) {
	//_streamSize = size;
    //一个std::list<Audio_Buff>()存放一天音频流的数据
	while (_audioQueueList.size() < size)
	{
		_audioQueueList.push_back(std::list<Audio_Buff>());
	}
	return 1;

}
int AudioBuffQueue::getStreamSize(){
    return (int)_audioQueueList.size();
}

int AudioBuffQueue::inputBuff(uint8_t* data, int len, int streamIndex, int64_t presentationTimeUs) {
	_lock.lock();
	int ret = 0;
	int size = (int)_audioQueueList.size();
	if (streamIndex < size)
	{
		ret = 1;
		Audio_Buff info;
		info.data = (uint8_t*)malloc(len);
        memcpy(info.data, data, len);
		info.dataLen = len;
		info.presentationTimeUs = presentationTimeUs;
		info.streamIndex = streamIndex;

		_audioQueueList[streamIndex].push_back(info);
		//if (streamIndex == size - 1)
		{
            //每插入最后一条音频流的数据就去检查一次，是否有一帧的数据已对齐
			checkAlignmentAll();
		}
	}
	_lock.unlock();
	return ret;
}

int AudioBuffQueue::popBuff() {
	_lock.lock();
	int ret = 0;
	if (!_alignmentQueue.empty())
	{
		std::vector<Audio_Buff>& list = _alignmentQueue.front();
		for (std::vector<Audio_Buff>::iterator iter = list.begin();iter != list.end();++iter)
		{
			free(iter->data);
		}
		_alignmentQueue.pop_front();
		ret = 1;
	}
	_lock.unlock();
	return ret;
}

uint32_t AudioBuffQueue::getCacheCount(){
    return (uint32_t)_alignmentQueue.size();
}

int64_t AudioBuffQueue::getFrontPresentationTimeUs() {
	_lock.lock();
	int64_t ret = -1;
	if (!_alignmentQueue.empty())
	{
		ret =  _alignmentQueue.front()[0].presentationTimeUs;
	}
	_lock.unlock();
	return ret;
}

int AudioBuffQueue::getFrontBuff(
	int indexA, uint8_t** pDataA, int* lenA,
    int indexB, uint8_t** pDataB, int* lenB) {
    
	_lock.lock();
	int ret = 0;
	if (!_alignmentQueue.empty())
	{
		std::vector<Audio_Buff>& list = _alignmentQueue.front();
		*pDataA = list[indexA].data;
		*lenA = list[indexA].dataLen;
		*pDataB = list[indexB].data;
		*lenB = list[indexB].dataLen;
		ret = 1;
	}
	_lock.unlock();
	return ret;
}

int AudioBuffQueue::getFrontBuff(uint8_t** out_data,uint32_t* out_dataLen){
    _lock.lock();
    int ret = 0;
    if (!_alignmentQueue.empty())
    {
        std::vector<Audio_Buff>& list = _alignmentQueue.front();
        uint32_t len = 0;
        for (std::vector<Audio_Buff>::iterator iter =  list.begin();iter != list.end();++iter) {
            Audio_Buff& info = *iter;
            len += info.dataLen;
        }
        if (_tempBuffLen < len) {
            _tempBuffLen = len;
            if (_tempBuff) {
                delete[] _tempBuff;
                _tempBuff = NULL;
            }
            _tempBuff = new uint8_t[_tempBuffLen];
        }
        uint8_t* temp = _tempBuff;
        for (std::vector<Audio_Buff>::iterator iter =  list.begin();iter != list.end();++iter) {
            Audio_Buff& info = *iter;
            memcpy(temp, info.data, info.dataLen);
            temp += info.dataLen;
        }

        
        *out_dataLen = len;
        *out_data = _tempBuff;
        ret = 1;
    }
    _lock.unlock();
    return ret;
}

void AudioBuffQueue::clean(){
    
    while (popBuff())
    {
        
    }
    _lock.lock();
    int size = (int)_audioQueueList.size();
    for (int i = 0;i< size;++i){

        std::list<Audio_Buff>& que = _audioQueueList[i];
        while (!que.empty()) {
            Audio_Buff& info = que.front();
            free(info.data);
            que.pop_front();
        }
    }
    _lock.unlock();
}


bool AudioBuffQueue::checkAlignmentAll() {
	std::list<Audio_Buff>& que = _audioQueueList[_audioQueueList.size()-1];
	std::vector<int64_t> pts;
	for (std::list<Audio_Buff>::iterator iter = que.begin();
		iter != que.end(); ++iter)
	{
		pts.push_back(iter->presentationTimeUs);
	}
	for (std::vector<int64_t>::iterator iter = pts.begin();iter!= pts.end();++iter)
	{
		checkAlignment(*iter);
	}
	return true;


}

//检查每天音频流是否都有pts为：presentationTimeUs的数据
bool AudioBuffQueue::checkAlignment(int64_t presentationTimeUs) {
	bool alignment = true;
	int size = (int)_audioQueueList.size();
    
    //遍历看看是否每条流的数据都有一个帧的pts等于presentationTimeUs
	for (int i = 0;i< size;++i){

		bool isFind = false;
		std::list<Audio_Buff>& que = _audioQueueList[i];
		for (std::list<Audio_Buff>::iterator iter = que.begin();
			iter != que.end(); ++iter)
		{
			if (iter->presentationTimeUs == presentationTimeUs)
			{
				isFind = true;
				break;
			}
		}
		if (!isFind)
		{
			alignment = false;
			break;
		}
	}
    //printf("presentationTimeUs:%lld alignment:%d \n",presentationTimeUs,alignment);
	if (alignment)
	{
		std::vector<Audio_Buff> aligList;
		for (int i = 0; i < size; ++i) {
			while (!_audioQueueList[i].empty())
			{
				Audio_Buff& info = _audioQueueList[i].front();
				bool isBreak = 
					info.presentationTimeUs == presentationTimeUs;
				if (isBreak)
				{
					aligList.push_back(info);
				}
				_audioQueueList[i].pop_front();
				if (isBreak)
				{
					break;
				}
				
			}
		}
        
		if (aligList.size() == size)
		{
			_alignmentQueue.push_back(aligList);
            
            _sampleTimeUss.push_back(presentationTimeUs);
		}
	}
	return alignment;

}

bool AudioBuffQueue::isHasSampleTimeUsData(int64_t sampleTimeUs){
    bool ret = false;
    _lock.lock();
    for (std::list<std::vector<Audio_Buff> >::iterator iter = _alignmentQueue.begin();
         iter != _alignmentQueue.end();++iter)
    {
        std::vector<Audio_Buff>& list = *iter;
        if (list[0].presentationTimeUs == sampleTimeUs) {
            ret = true;
            break;
        }
        
    }
    _lock.unlock();
    return ret;
}

bool AudioBuffQueue::outputSampleTimeUs(int64_t* out_sampleTimeUs){
    if (!out_sampleTimeUs) {
        return false;
    }
    _lock.lock();
    bool ret = false;
    if (!_sampleTimeUss.empty())
    {
        *out_sampleTimeUs = _sampleTimeUss.front();
        _sampleTimeUss.pop_front();
        ret = true;
    }
    _lock.unlock();
    return ret;
}
